import {GenCfg} from "./GenCfg";
import * as fs from "fs";
import {GenCode} from "../expressExt/GenCode";
import {MapString, sdf, MapNumber} from "../expressExt/public/sdf";
import {Meta} from "../expressExt/public/Meta";
import {exp} from "../expressExt/exp";
import {sql} from "../expressExt/db/Isql";
import {ObjectID} from "mongodb";

export class GenKt {
    static apiFile = "api.kt";

    static getMenu() {
        return GenCfg.codeOutMenu + "/kt/";
    }

    /**
     * 生成kt代码
     * @param url
     * @param modReq 接口入参
     * @param resp 接口返回对象
     * @param isPost
     */
    static genFile(url: string, modReq: { new(): any;}, resp: any, isPost: "false"|"true") {
        //文档目录
        if (!fs.existsSync(GenKt.getMenu()))
            fs.mkdirSync(GenKt.getMenu());

        //api文件
        let fileTemp = GenKt.getMenu() + GenKt.apiFile + ".temp";
        let file = GenKt.getMenu() + GenKt.apiFile;

        if (fs.existsSync(file))
            return;

        //收尾
        if (url == null) {
            if (GenCfg.genCount == 1)
                return;
            fs.appendFileSync(fileTemp, "\r\n\r\n/////////api end//////////\r\n}");
            fs.renameSync(fileTemp, file);
            return;
        }

        //头
        if (GenCfg.genCount == 1) {
            fs.appendFileSync(fileTemp,
                "package com.df.apis\r\n" +
                "\r\n" +
                "import java.util.*\r\n" +
                "import com.xtools.model.Var\r\n" +
                "\r\n" +
                "\r\n" +
                "object api {\r\n" +
                "\r\n");
        }

        //接口注释
        let apiComment = GenCode.readComment(GenCfg.expFuncStr, url, GenCfg.ExpressExtCommentPos);

        let nameUrl = GenCode.fixUrl(url)
        let name = GenCode.fixNmaeUpperCase(nameUrl);


        //入参
        let paras = new modReq();

        let apiFunc =
            "    /**\r\n" +
            "     * " + apiComment + "\r\n";

        for (let n in paras) {
            apiFunc +=
                "     * @param " + n + "\r\n" +
                "     *            " + GenCode.readComment(modReq, "this." + n, 1) + "\r\n";
        }

        apiFunc +=
            "     * @param faildMsg\r\n" +
            "     *            异步模式下是否显示进度条,且当status==0时弹出msg消息提示并忽略res回调(\r\n" +
            "     * @param res\r\n" +
            "     *            结果回调,传null会同步阻塞执行并返回结果RespMsg\r\n" +
            "     */\r\n" +
            "    @JvmStatic\r\n" +
            "    @JvmOverloads\r\n" +
            "    fun " + name + "(\r\n";
        for (let n in paras) {
            if (n == "uid" || n == "token")
                continue;
            let parType = GenKt.objTypeName(paras[n], nameUrl + "_" + n, modReq, n);
            apiFunc += "            " + n + ": " + parType + ",\r\n";
        }

        //出参
        let respType = GenKt.objTypeName(resp, nameUrl);
        let respIsArray = respType.startsWith("ArrayList") ? "Array" : "";

        apiFunc +=
            "            faildMsg: Boolean = false,\r\n" +
            "            res: ((r: RespMsg<" + respType + ">) -> Unit)?): RespMsg<" + respType + "> {\r\n" +
            "        val paras = HashMap<String, Any>();\r\n";

        let noValid = exp.getNoValid(modReq);
        for (let n in paras) {
            if (n == "uid" || n == "token")
                continue;

            apiFunc += "        paras[\"" + n + "\"] = " + n + "\r\n";
        }

        apiFunc +=
            "        paras[\"uid\"] = Var.getUser().uid\r\n" +
            "        paras[\"token\"] = Var.getUser().sid\r\n";

        apiFunc +=
            "        return ApiHttp.send" + respIsArray + "(paras, \"" + url + "\", res, " + isPost + ", faildMsg)\r\n" +
            "    }\r\n\r\n";


        fs.appendFileSync(fileTemp, apiFunc);
    }

    /**
     * 类型map
     * @type {{}}
     */
    static typeMap: MapNumber<string> = {};

    /**
     *
     * @param obj 对象
     * @param name 对象类名
     * @param clas 所属类
     * @param field 对象字段名
     * @returns {string}
     */
    static objTypeName(obj: any, name: string, clas?: any, field?: string) {


        let respType = "[未知类型]";
        if (typeof obj === "string" || obj instanceof String)
            respType = "String";
        else if (typeof obj === "number" || obj instanceof Number)
            respType = "Long";
        else if (obj instanceof Array) {
            let arrType = "";
            if (obj.length > 0)
                arrType = GenKt.objTypeName(obj[0], name);
            else if (clas && field) {
                let typeClas = Meta.getArrayType(clas, field);
                if (!typeClas)
                    typeClas = sdf.getArrayType(obj);

                if (typeClas)
                    arrType = GenKt.objTypeName(new typeClas(), name);
            }
            respType = "ArrayList<" + arrType + ">";
        }
        else if (obj instanceof exp) {
            respType = "String";
        }
        else if (obj instanceof ObjectID) {
            respType = "String";
        }
        else if (typeof obj === "object") {
            if (obj == null)
                return "String";
            let clas2 = obj.constructor;
            let className = name;
            if (clas2.name != "" && clas2.name !== "Object") {
                className = clas2.name;
            }

            GenKt.clearObjVal(obj);
            let nameCode = sdf.hashCode(JSON.stringify(obj));
            let clasMap = GenKt.typeMap[nameCode];
            //有相同的类型,直接返回
            if (clasMap) {
                return clasMap;
            }
            else {
                //生成新的类型
                if (clas2.name === "Object")
                    GenKt.genNewType(clas, className, obj);
                else
                    GenKt.genNewType(clas2, className, obj);
                GenKt.typeMap[nameCode] = className;
                return className;
            }
        }
        return respType;
    }


    static clearObjVal(obj: any) {
        for (let i in obj) {
            let t = typeof obj[i];
            if (t === "string") {
                obj[i] = "";
            }
            else if (obj[i] instanceof ObjectID) {
                obj[i] = "";
            }
            else if (t === "number") {
                obj[i] = 0;
            }
        }
    }

    /**
     * 生成新的类型写入文件
     * @param clas
     * @param className
     */
    static genNewType(clas: any, className: string, obj?: any) {
        let str =
            "package com.df.apis\r\n" +
            "\r\n" +
            "class " + className + "(   \r\n";
        if (!obj) {
            obj = new clas();
        }
        for (let n in obj) {
            let nType = GenKt.objTypeName(obj[n], className + "_" + n, clas, n);
            let val = nType + "()"
            if (nType == "String")
                val = "\"\""
            else if (nType == "Long")
                val = "0L"
            str +=
                "        /**\r\n" +
                "         * " + GenCode.readComment(clas, "this." + n, 1) + "\r\n" +
                "         */\r\n" +
                "        var " + n + ": " + nType + " = " + val + ",\r\n\r\n";
        }

        str = str.substr(0, str.length - 5);
        str +=
            ") {\r\n" +
            "\r\n" +
            "}"

        fs.writeFileSync(GenKt.getMenu() + className + ".kt", str);
    }
}